package puzzle.nurikabe.solver;

import puzzle.common.data.HatanException;
import puzzle.common.solver.BoardRule;
import puzzle.nurikabe.data.NurikabeBoard;
import puzzle.nurikabe.data.ShimaState;
import puzzle.nurikabe.data.StateUtil;

class BoardwiseShimaPotentialRule implements BoardRule<NurikabeBoard> {

	private static final int IMPOSSIBLE = 0;
	private static final int MULTIPLE = -1;

	public boolean apply(NurikabeBoard b) throws HatanException {
		int[] possibleShimas = new int[b.width * b.height];

		for (ShimaState s : b.getShimaStates()) {
			for (int y = s.lefttop.y; y <= s.rightbottom.y; y++) {
				for (int x = s.lefttop.x; x <= s.rightbottom.x; x++) {
					int i = x + y * b.width;
					if (possibleShimas[i] != MULTIPLE) {
						if (s.getPotential(x, y) != 0) {
							if (possibleShimas[i] == IMPOSSIBLE) {
								possibleShimas[i] = s.i;
							} else {
								possibleShimas[i] = MULTIPLE;
							}
						}
					}
				}
			}
		}

		boolean isChanged = false;
		int i = 0;
		for (int y = 0; y < b.height; y++) {
			for (int x = 0; x < b.width; x++) {
				int n = b.getBoardState(x, y);
				int k = possibleShimas[i++];

				switch (k) {
				case IMPOSSIBLE:
					isChanged |= b.setKabe(x, y);
					break;
				case MULTIPLE:
					break;
				default:
					if (StateUtil.isUndeterminedShima(n)) {
						ShimaState s = b.getShimaState(k);
						isChanged |= b.updateShima(x, y, StateUtil.encodeOwningShima(n, s.i));
					}
					break;
				}

			}
		}
		return isChanged;
	}
}
